home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / msysjour / vol06 / 01 / wintro4 / graph.c < prev    next >
C/C++ Source or Header  |  1990-12-31  |  16KB  |  467 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <windows.h>
  4. #include "stock.h"
  5.  
  6. void FAR PASCAL HandleSelectionState(LPDRAWITEMSTRUCT lpdis, int inflate);
  7. void FAR PASCAL HandleFocusState(LPDRAWITEMSTRUCT lpdis, int inflate);
  8. void FAR PASCAL DrawEntireItem(LPDRAWITEMSTRUCT lpdis, int inflate);
  9.  
  10.  
  11. BOOL FAR PASCAL
  12. GraphOptionsDlgProc(hDlg, message, wParam, lParam)
  13.   HWND hDlg;
  14.   unsigned message;
  15.   WORD wParam;
  16.   LONG lParam;
  17. {
  18.   int         iPen; 
  19.   char        szBuf[80];
  20.   static HANDLE      hStockInfo = NULL;
  21.   static LPSTOCKINFO lpStockInfo = (LPSTOCKINFO) NULL;
  22.   LPGRAPHINFO lpGraphInfo;
  23.   HWND        hWnd;
  24.   BOOL        bTranslated;
  25.  
  26.  
  27.   switch (message)
  28.   {
  29.     case WM_INITDIALOG :
  30.       if ((hStockInfo = (HANDLE) lParam) == NULL)
  31.       {
  32.         EndDialog(hDlg, IDCANCEL);
  33.         return TRUE;
  34.       }
  35.  
  36.       if ((lpStockInfo = (LPSTOCKINFO) GlobalLock(hStockInfo)) == NULL)
  37.       {
  38.         EndDialog(hDlg, IDCANCEL);
  39.         return TRUE;
  40.       }
  41.   
  42.       lpGraphInfo = &lpStockInfo->StockFile.graphinfo;
  43.  
  44.       /*
  45.         If the ticks array has some memory allocated to it, it means
  46.         that we are dealing with an existing stock. If not, then we
  47.         are creating a new stock.
  48.       */
  49.       if (lpStockInfo->hTicks != NULL)
  50.       {
  51.         SetDlgItemText(hDlg, ID_SYMBOL, lpStockInfo->StockFile.szStock);
  52.         SetDlgItemInt(hDlg, ID_MINPRICE, (int) lpGraphInfo->dwMinPrice, FALSE);
  53.         SetDlgItemInt(hDlg, ID_MAXPRICE, (int) lpGraphInfo->dwMaxPrice, FALSE);
  54.         SetDlgItemInt(hDlg, ID_FACTOR, (int) lpGraphInfo->dwScaleFactor, FALSE);
  55.         SetDlgItemInt(hDlg, ID_TICKINT, (int) lpGraphInfo->dwTickInterval, FALSE);
  56.         SetDlgItemInt(hDlg, ID_DENOMINATOR, (int) lpGraphInfo->iDenominator, FALSE);
  57.  
  58.         if (lpStockInfo->dwFlags & STATE_HAS_VGRID)
  59.           CheckDlgButton(hDlg, ID_VERTGRID, TRUE);
  60.         if (lpStockInfo->dwFlags & STATE_HAS_HGRID)
  61.           CheckDlgButton(hDlg, ID_HORZGRID, TRUE);
  62.  
  63.         EnableWindow(GetDlgItem(hDlg, ID_SYMBOL), FALSE);
  64.       }
  65.       else
  66.       {
  67.         lpGraphInfo->iGridPen = 0;
  68.       }
  69.  
  70.  
  71.       /* 
  72.         Fill the listbox with pen ids 
  73.       */ 
  74.       for (iPen = 0;  iPen < PS_NULL;  iPen++) 
  75.         SendDlgItemMessage(hDlg, ID_GRIDSTYLE, CB_ADDSTRING, 0, (LONG) iPen); 
  76.       SendDlgItemMessage(hDlg,ID_GRIDSTYLE,CB_SETCURSEL,lpGraphInfo->iGridPen,0L);
  77.       return TRUE;
  78.  
  79.  
  80.     case WM_MEASUREITEM : 
  81.     { 
  82.       LPMEASUREITEMSTRUCT lpMI = (LPMEASUREITEMSTRUCT) (LPSTR) lParam; 
  83.       lpMI->itemWidth  = 42; 
  84.       lpMI->itemHeight = 20; 
  85.       break; 
  86.     } 
  87.  
  88.     case WM_DRAWITEM : 
  89.     { 
  90.       LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) (LPSTR) lParam; 
  91.  
  92.       if (lpdis->itemID == -1)
  93.       {
  94.         HandleFocusState(lpdis, -5);
  95.         break;
  96.       }
  97.  
  98.       switch (lpdis->itemAction) 
  99.       { 
  100.         case ODA_DRAWENTIRE: 
  101.           DrawEntireItem(lpdis, -4); 
  102.           break; 
  103.  
  104.         case ODA_SELECT: 
  105.           HandleSelectionState(lpdis, 0); 
  106.           break; 
  107.  
  108.         case ODA_FOCUS: 
  109.           HandleFocusState(lpdis, -2); 
  110.           break; 
  111.       } 
  112.  
  113.       break; 
  114.     } 
  115.  
  116.  
  117.     case WM_COMMAND :
  118.       switch (wParam)
  119.       {
  120.         case IDOK :
  121.           lpGraphInfo = &lpStockInfo->StockFile.graphinfo;
  122.  
  123.           if (lpStockInfo->hTicks == NULL)
  124.           {
  125.             GetDlgItemText(hDlg, ID_SYMBOL, szBuf, sizeof(szBuf));
  126.             if (*szBuf == '\0')
  127.             {
  128.               MessageBox(hWndMain, "You must fill in the name of the stock.", "Error", MB_OK);
  129.               return TRUE;
  130.             }
  131.             strcat(szBuf, ".STO");
  132.             lstrcpy(lpStockInfo->szFileName, szBuf);
  133.  
  134.             lpStockInfo->StockFile.dwMagic = MAGIC_COOKIE;
  135.             if ((lpStockInfo->hTicks = GlobalAlloc(GMEM_MOVEABLE, (DWORD) sizeof(TICK) * 64)) == NULL)
  136.             {
  137.               MessageBox(hWndMain, "Can't allocate the ticker array", "Error", MB_OK);
  138.               goto bye;
  139.             }
  140.             lpStockInfo->nTicksAllocated = 64;
  141.             lpStockInfo->StockFile.nTicks = 0;
  142.  
  143.             /*
  144.               Create a window for this guy
  145.             */
  146.             hWnd = lpStockInfo->hWnd = GraphCreateWindow((LPSTR) szBuf);
  147.             SetWindowWord(lpStockInfo->hWnd, 0, hStockInfo);
  148.             lpStockInfo->dwFlags |= STATE_DIRTY;
  149.           }
  150.  
  151.           GetDlgItemText(hDlg, ID_SYMBOL, lpStockInfo->StockFile.szStock, 
  152.                                       sizeof(lpStockInfo->StockFile.szStock));
  153.           lpGraphInfo->dwMinPrice = GetDlgItemLong(hDlg, ID_MINPRICE,
  154.                                       (BOOL FAR *) &bTranslated, FALSE);
  155.           lpGraphInfo->dwMaxPrice = GetDlgItemLong(hDlg, ID_MAXPRICE,
  156.                                       (BOOL FAR *) &bTranslated, FALSE);
  157.           lpGraphInfo->dwScaleFactor = GetDlgItemLong(hDlg, ID_FACTOR,
  158.                                       (BOOL FAR *) &bTranslated, FALSE);
  159.           lpGraphInfo->dwTickInterval = GetDlgItemLong(hDlg, ID_TICKINT,
  160.                                       (BOOL FAR *) &bTranslated, FALSE);
  161.           lpGraphInfo->iDenominator = GetDlgItemInt(hDlg, ID_DENOMINATOR,
  162.                                       (BOOL FAR *) &bTranslated, FALSE);
  163.           lpGraphInfo->iGridPen = (WORD)
  164.                   SendDlgItemMessage(hDlg, ID_GRIDSTYLE, CB_GETCURSEL, 0, 0L);
  165.  
  166.           lpStockInfo->dwFlags &= ~(STATE_HAS_VGRID | STATE_HAS_HGRID);
  167.           if (IsDlgButtonChecked(hDlg, ID_VERTGRID))
  168.             lpStockInfo->dwFlags |= STATE_HAS_VGRID;
  169.           if (IsDlgButtonChecked(hDlg, ID_HORZGRID))
  170.             lpStockInfo->dwFlags |= STATE_HAS_HGRID;
  171.  
  172. bye:
  173.           InvalidateRect(lpStockInfo->hWnd, (LPRECT) NULL, TRUE);
  174.           GlobalUnlock(hStockInfo);
  175.           EndDialog(hDlg, IDOK);
  176.           break;
  177.  
  178.         case IDCANCEL:
  179.           GlobalUnlock(hStockInfo);
  180.           EndDialog(hDlg, IDCANCEL);
  181.           break;
  182.       }
  183.       return TRUE;
  184.  
  185.   } /* end switch (message) */
  186.  
  187.   return FALSE;
  188. }
  189.  
  190.  
  191. /**************************************************************************** 
  192.  *                                                                          * 
  193.  *  FUNCTION   : HandleSelectionState(LPDRAWITEMSTRUCT, int)                * 
  194.  *                                                                          * 
  195.  *  PURPOSE    : Handles a change in an item selection state. If an item is * 
  196.  *               selected, a black rectangular frame is drawn around that   * 
  197.  *               item; if an item is de-selected, the frame is removed.     * 
  198.  *                                                                          * 
  199.  *  COMMENT    : The black selection frame is slightly larger than the gray * 
  200.  *               focus frame so they won't paint over each other.           * 
  201.  *                                                                          * 
  202.  ****************************************************************************/ 
  203. void FAR PASCAL HandleSelectionState(lpdis, inflate) 
  204.   LPDRAWITEMSTRUCT  lpdis; 
  205.   int               inflate; 
  206.   HBRUSH hbr = (lpdis->itemState & ODS_SELECTED) ? GetStockObject(BLACK_BRUSH)
  207.                                 : CreateSolidBrush(GetSysColor(COLOR_WINDOW)); 
  208.   FrameRect(lpdis->hDC, (LPRECT) &lpdis->rcItem, hbr); 
  209.   DeleteObject (hbr); 
  210.  
  211.  
  212. /**************************************************************************** 
  213.  *                                                                          * 
  214.  *  FUNCTION   : HandleFocusState(LPDRAWITEMSTRUCT, int)                    * 
  215.  *                                                                          * 
  216.  *  PURPOSE    : Handle a change in item focus state. If an item gains the  * 
  217.  *               input focus, a gray rectangular frame is drawn around that * 
  218.  *               item; if an item loses the input focus, the gray frame is  * 
  219.  *               removed.                                                   * 
  220.  *                                                                          * 
  221.  *  COMMENT    : The gray focus frame is slightly smaller than the black    * 
  222.  *               selection frame so they won't paint over each other.       * 
  223.  *                                                                          * 
  224.  ****************************************************************************/ 
  225. void FAR PASCAL HandleFocusState(lpdis, inflate) 
  226.   LPDRAWITEMSTRUCT  lpdis; 
  227.   int      inflate; 
  228.   RECT  rc; 
  229.   HBRUSH  hbr; 
  230.  
  231.   /* Resize rectangle to place focus frame between the selection 
  232.    * frame and the item. 
  233.    */ 
  234.   CopyRect ((LPRECT)&rc, (LPRECT)&lpdis->rcItem); 
  235.   InflateRect ((LPRECT)&rc, inflate, inflate); 
  236.  
  237.   if (lpdis->itemState & ODS_FOCUS) 
  238.     /* gaining input focus -- paint a gray frame */ 
  239.     hbr = GetStockObject(GRAY_BRUSH); 
  240.   else 
  241.     /* losing input focus -- remove (paint over) frame */ 
  242.     hbr = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); 
  243.  
  244.   FrameRect(lpdis->hDC, (LPRECT)&rc, hbr); 
  245.   DeleteObject (hbr); 
  246.  
  247. /**************************************************************************** 
  248.  *                                                                          * 
  249.  *  FUNCTION   : DrawEntireItem(LPDRAWITEMSTRUCT, int)                      * 
  250.  *                                                                          * 
  251.  *  PURPOSE    : Draws an item and frames it with a selection frame and/or  * 
  252.  *               a focus frame when appropriate.                            * 
  253.  *                                                                          * 
  254.  ****************************************************************************/ 
  255. void FAR PASCAL DrawEntireItem(lpdis, inflate) 
  256.   LPDRAWITEMSTRUCT  lpdis; 
  257.   int      inflate; 
  258.   RECT   rc; 
  259.   HANDLE hOldPen; 
  260.   HPEN   hPen; 
  261.  
  262.   if (lpdis->itemData < 0)
  263.     return;
  264.  
  265.   /* Resize rectangle to leave space for frames */ 
  266.   CopyRect ((LPRECT)&rc, (LPRECT)&lpdis->rcItem); 
  267.   InflateRect ((LPRECT)&rc, inflate, inflate); 
  268.  
  269.   if (lpdis->itemState & ODS_FOCUS) 
  270.     hPen = CreatePen((int) lpdis->itemData, 1, RGB(0xFF, 0xFF, 0xFF)); 
  271.   else
  272.     hPen = CreatePen((int) lpdis->itemData, 1, RGB(0, 0, 0)); 
  273.   hOldPen = SelectObject(lpdis->hDC, hPen); 
  274.  
  275. #if 0
  276. {
  277.   char szMsg[80];
  278.   sprintf(szMsg,
  279.   "rc:[%d %d %d %d]  itemID:%d  itemAction:%x  itemState:%x  itemData:%ld",
  280.    rc.left, rc.top, rc.right, rc.bottom, lpdis->itemID, lpdis->itemAction,
  281.    lpdis->itemState, lpdis->itemData);
  282.   MessageBox(hWndMain, szMsg, "DrawEntireItem", MB_OK);
  283. }
  284. #endif
  285.  
  286.   MoveTo(lpdis->hDC, rc.left,  rc.top + (rc.bottom - rc.top) / 2); 
  287.   LineTo(lpdis->hDC, rc.right, rc.top + (rc.bottom - rc.top) / 2); 
  288.  
  289.   SelectObject(lpdis->hDC, hOldPen); 
  290.   DeleteObject(hPen); 
  291.  
  292.   /* Draw or erase appropriate frames */ 
  293.   HandleSelectionState(lpdis, inflate + 4); 
  294.   HandleFocusState(lpdis, inflate + 2); 
  295.  
  296.  
  297. int PASCAL GraphWndPaint(HWND hWnd, HDC hDC, LPSTOCKINFO lpStockInfo)
  298. {
  299.   RECT         r;
  300.   int          i, y;
  301.   int          xGraph, yGraph;
  302.   LPTICK       lpTick;
  303.   int          rangeHigh,
  304.                rangeLow,
  305.                xPixelsPerDate;
  306.   int          yAxisStart, xAxisStart;
  307.   HANDLE       hOldPen;
  308.   HPEN         hPen;
  309.   TEXTMETRIC   tm;
  310.   char         szBuf[80];
  311.  
  312.   if (lpStockInfo->StockFile.nTicks == 0)
  313.     return TRUE;
  314.  
  315.   /*
  316.     Get the client dimensions of the current stock window and figure out the
  317.     width and height of the graph.
  318.   */
  319.   GetClientRect(hWnd, (LPRECT) &r);
  320.   yGraph = r.bottom - r.top;
  321.   xGraph = r.right - r.left;
  322.  
  323.   /*
  324.     Get the low and high range into local variables.
  325.   */
  326.   rangeHigh = (int) lpStockInfo->StockFile.graphinfo.dwMaxPrice;
  327.   rangeLow  = (int) lpStockInfo->StockFile.graphinfo.dwMinPrice;
  328.  
  329.   /*
  330.     Get the metrics of the current font.
  331.   */
  332.   GetTextMetrics(hDC, (LPTEXTMETRIC) &tm);
  333.  
  334.   if ((lpTick = (LPTICK) GlobalLock(lpStockInfo->hTicks)) == NULL)
  335.     return FALSE;
  336.  
  337.  
  338.   /*
  339.     This code is for WINTRO 4
  340.   */
  341.   y = 0;
  342.   for (i = 0;  i < lpStockInfo->StockFile.nTicks;  i++)
  343.   {
  344.     sprintf(szBuf, "%d) Price %ld", i+1, lpTick[i].price);
  345.     TextOut(hDC, 0, y, szBuf, strlen(szBuf));
  346.     y += tm.tmHeight;
  347.   }
  348.   goto bye;
  349.  
  350.  
  351.  
  352.   /*
  353.     Set up the mapping mode. Y-axis points up and X-axis points right.
  354.   */
  355.   SetMapMode(hDC, MM_ANISOTROPIC);
  356.   SetWindowOrg(hDC, 0, 0);
  357.   SetViewportOrg(hDC, 0, yGraph);
  358.   SetWindowExt(hDC,  xGraph, yGraph);
  359.   SetViewportExt(hDC, xGraph, -yGraph);
  360.  
  361.   sprintf(szBuf, "%d", rangeHigh);
  362.   yAxisStart = strlen(szBuf) * (tm.tmAveCharWidth + 1);
  363.   xAxisStart = tm.tmHeight + (tm.tmHeight/2);
  364.   xPixelsPerDate = xGraph / lpStockInfo->StockFile.nTicks;
  365.  
  366.   /*
  367.     Draw the axises. First the Y-axis, then the X-axis.
  368.   */
  369.   MoveTo(hDC, yAxisStart, xAxisStart);
  370.   LineTo(hDC, yAxisStart, yGraph);
  371.   MoveTo(hDC, yAxisStart, xAxisStart);
  372.   LineTo(hDC, xGraph,     xAxisStart);
  373.  
  374.   /*
  375.     Draw the hash marks for the x-axis
  376.   */
  377.   for (i = 1;  i < lpStockInfo->StockFile.nTicks;  i++)
  378.   {
  379.     int x = i * xPixelsPerDate + yAxisStart;
  380.     int iTextLen;
  381.     MoveTo(hDC, x, xAxisStart-2);
  382.     LineTo(hDC, x, xAxisStart+2);
  383.     sprintf(szBuf, "%d", i+1);
  384.     iTextLen = strlen(szBuf) * tm.tmAveCharWidth;
  385.     /*
  386.       Output the x-axis text centered over the hash mark
  387.     */
  388.     TextOut(hDC, x - (iTextLen >> 1), xAxisStart-2, szBuf, strlen(szBuf));
  389.   }
  390.  
  391.   /*
  392.     Draw the hash marks for the y-axis
  393.   */
  394.   for (i = rangeLow;  i < rangeHigh;  i++)
  395.   {
  396.     int y = (i - rangeLow) * yGraph / (rangeHigh - rangeLow) + xAxisStart;
  397.     MoveTo(hDC, yAxisStart-4, y);
  398.     LineTo(hDC, yAxisStart+4, y);
  399.     sprintf(szBuf, "%d", i);
  400.     TextOut(hDC, 0, y + (tm.tmHeight >> 1), szBuf, strlen(szBuf));
  401.   }
  402.  
  403.  
  404.   /*
  405.     Figure out how many pixels wide each entry should be. This is equal
  406.     to the width of the graph divided by the number of ticks to be plotted.
  407.   */
  408.   MoveTo(hDC, yAxisStart, xAxisStart + 
  409.           ((int) lpTick[0].price - rangeLow) * yGraph / (rangeHigh - rangeLow));
  410.   if (lpStockInfo->StockFile.nTicks == 1)
  411.   {
  412.     int x = i * xPixelsPerDate;
  413.     int y = ((int)lpTick[i].price - rangeLow) * yGraph / (rangeHigh-rangeLow);
  414.     Ellipse(hDC, x-2, y-2, x+2, y+2);
  415.   }
  416.   else
  417.   {
  418.     for (i = 1;  i < lpStockInfo->StockFile.nTicks;  i++)
  419.     {
  420.       int x = i * xPixelsPerDate;
  421.       int y = ((int) lpTick[i].price - rangeLow) * yGraph / 
  422.               (rangeHigh - rangeLow);
  423.       LineTo(hDC, x + yAxisStart, y + xAxisStart);
  424.     }
  425.   }
  426.  
  427.   /*
  428.     Now draw the horizontal and vertical grid lines.
  429.   */
  430.   hPen = CreatePen(lpStockInfo->StockFile.graphinfo.iGridPen, 1, RGB(0, 0, 0));
  431.   hOldPen = SelectObject(hDC, hPen);
  432.  
  433.   if (lpStockInfo->dwFlags & STATE_HAS_VGRID)
  434.   {
  435.     for (i = 0;  i < lpStockInfo->StockFile.nTicks;  i++)
  436.     {
  437.       int x = (i+1) * xPixelsPerDate + yAxisStart;
  438.       MoveTo(hDC, x, xAxisStart);
  439.       LineTo(hDC, x, yGraph);
  440.     }
  441.   }
  442.  
  443.   if (lpStockInfo->dwFlags & STATE_HAS_HGRID)
  444.   {
  445.     for (i = rangeLow+1;  i < rangeHigh;  i++)
  446.     {
  447.       int y = (i - rangeLow) * yGraph / (rangeHigh - rangeLow);
  448.       MoveTo(hDC, yAxisStart, y + xAxisStart);
  449.       LineTo(hDC, xGraph, y + xAxisStart);
  450.     }
  451.   }
  452.  
  453.   SelectObject(hDC, hOldPen);
  454.   DeleteObject(hPen);
  455.  
  456. bye:
  457.   GlobalUnlock(lpStockInfo->hTicks);
  458.   return TRUE;
  459. }
  460.  
  461.